package readfile;

/**
 * Created by 瀚文 on 2016/11/9.
 */
import java.io.*;
import java.lang.*;
public class WavDataParsing {
    private String filename = null;
    private int[] data = null;   //存储数据的数组
    private int len = 0;  //起始地址
    private String chunkID = null;  //根节点名称"RIFF"
    static private int lenchunkID = 4;
    private long chunksize = 0;   //从这个字段开始的长度
    static private int lenchunksize = 4;
    private String waveflag = null;   //文件格式"wave"
    static private int lenwaveflag = 4;
    private String fmtubchunk = null;  //Subchunk1_ID= "fmt "
    static private int lenfmtubchunk = 4;
    private long subchunk1size = 0;   //格式节点除去前两个字段的长度
    static private int lensubchunk1size = 4;
    private int audioformat = 0;   //音频格式，1为PCM格式，其他为各种压缩格式
    static private int lenaudioformat = 2;
    private int numchannels = 0;      //声道数
    static private int lennumchannels = 2;
    private long samplerate = 0;   //采样率
    static private int lensamplerate = 2;
    private long byterate = 0;   //比特率/8
    static private int lenbyterate = 4;
    private int blockalign = 0;
    static private int lenblockling = 2;
    private int bitspersample = 0;    //位深度
    static private int lenbitspersample = 2;
    private int extraparamsize = 0;
    static private int lenextraparamsize = 2;
    private String datasubchunk = null;   //数据节点的名称Subchunk2_ID= "data"= 0x64617461
    static private int lendatasubchunk = 4;
    private long subchunk2size = 0;   //数据节点的长度
    static private int lensubchunk2size = 4;
    private FileInputStream fis = null;
    private BufferedInputStream bis = null;
    private ByteArrayOutputStream bos = null;
    private boolean issuccess = false;
    //构造函数
    public WavDataParsing(String filename) {
        this.initReader(filename);
    }
    // 判断是否创建wav读取器成功
    public boolean isSuccess() {
        return issuccess;
    }
    // 获取每个采样的编码长度，8bit或者16bit
    public int getBitPerSample(){
        return this.bitspersample;
    }
    // 获取采样率
    public long getSampleRate(){
        return this.samplerate;
    }
    // 获取声道个数，1代表单声道 2代表立体声
    public int getNumChannels(){
        return this.numchannels;
    }
    // 获取数据长度，也就是一共采样多少个
    public int getDataLen(){
        return this.len;
    }
    // 获取数据
    // 数据是一个byte数组，data[n]代表第n个采样值
    public int[] getData(){
        return this.data;
    }
    private void initReader(String filename){
        this.filename = filename;
        try {
            fis = new FileInputStream(this.filename);
            bis = new BufferedInputStream(fis);
            this.chunkID= readString(lenchunkID);
            if(!chunkID.endsWith("RIFF")){
                throw new IllegalArgumentException("RIFF miss, " + filename + " is not a wave file.");}
            this.chunksize = readLong();
            this.waveflag = readString(lenwaveflag);
            if(!waveflag.endsWith("WAVE"))
                throw new IllegalArgumentException("WAVE miss, " + filename + " is not a wave file.");
            this.fmtubchunk = readString(lenfmtubchunk);
            if(!fmtubchunk.endsWith("fmt "))
                throw new IllegalArgumentException("fmt miss, " + filename + " is not a wave file.");
            this.subchunk1size = readLong();
            this.audioformat = readInt();
            this.numchannels = readInt();
            this.samplerate = readLong();
            this.byterate = readLong();
            this.blockalign = readInt();
            this.bitspersample = readInt();
            this.extraparamsize = readInt();
            this.datasubchunk = readString(lendatasubchunk);
            if(!datasubchunk.endsWith("data"))
                throw new IllegalArgumentException("data miss, " + filename + " is not a wave file.");
            this.subchunk2size = readLong();
            this.len = (int)(this.subchunk2size/(this.bitspersample/8)/this.numchannels);
            this.data = new int[this.len];

            for (int i = 0; i < this.len; ++i) {
                this.data[i] = this.readInt();
            }

            issuccess = true;

        } catch (Exception e) {
            e.printStackTrace();
        }
        finally{
            try{
                if(bis != null)
                    bis.close();
                if(fis != null)
                    fis.close();
                /*if(bos != null)
                    bos.close();*/
            }
            catch(Exception e){
                e.printStackTrace();
            }
        }
    }
    private String readString(int len) {
        byte[] buf = new byte[len];
        try {
            if (bis.read(buf) != len)
                throw new IOException("no more data!!!");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new String(buf);
    }

    private int readInt() {
        byte[] buf = new byte[2];
        int res = 0;
        try {
            if (bis.read(buf) != 2)
                throw new IOException("no more data!!!");
            res = (buf[0] & 0x000000FF) | ((int)( buf[1]) << 8);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return res;
    }

    private long readLong() {
        long res = 0;
        try {
            long[] l = new long[4];
            for (int i = 0; i < 4; ++i) {
                l[i] = bis.read();
                if (l[i] == -1) {
                    throw new IOException("no more data!!!");
                }
            }
            res = l[0] | (l[1] << 8) | (l[2] << 16) | (l[3] << 24);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return res;
    }

}